//
//  InputData.cpp
//  HelloCpp
//
//  Created by Nguyen Cong Huy on 10/7/14.
//
//

#include "InputData.h"
#include "Utils.h"
#include <fstream>
#include <sstream>
#include <vector>
#include "Vehicle.h"

#define kNumFieldData 13

using namespace std;

vector<string> &split(const string &s, char delim, vector<string> &elems) {
    stringstream ss(s);
    string item;
    while (getline(ss, item, delim)) {
        elems.push_back(item);
    }
    return elems;
}

vector<string> split(const string &s, char delim) {
    vector<string> elems;
    split(s, delim, elems);
    return elems;
}

InputData::InputData() {
    vehicleDataArray = new CCArray();
    clearData();
}

void InputData::clearData() {
    minStartTime = 1000000;
    maxStartTime = 0;
    vehicleDataArray->removeAllObjects();
}

void InputData::addVehicleData(VehicleData* data) {
    
}

void InputData::removeVehicleData(VehicleData* data) {
    
}

bool InputData::readAppendDataFromFile(const char* fileName) {
    CCLog("readAppendDataFromFile %s", fileName);
    ifstream fileStream;
    string dataString;
    bool isSuccess = false;
    
    fileStream.open(fileName);
    if (fileStream.is_open()) {
        isSuccess = true;
        while (fileStream.eof() == false) {
            getline(fileStream, dataString);
            addVehicleDataFromString(dataString);
        }
    }
    fileStream.close();
    return isSuccess;
}

void InputData::addVehicleDataFromString(string dataString) {
    vector<string> lineVector = split(dataString, '\r');
    int lineIndex = 0;
    for(vector<string>::iterator i = lineVector.begin(); i != lineVector.end(); i++) {
        string lineString = *i;
        VehicleData* vehicleData = createVehicleDataFromLine(lineString);
        if(vehicleData) {
            vehicleDataArray->addObject(vehicleData);
            if(vehicleData->time < minStartTime) {
                minStartTime = vehicleData->time;
            }
            if(vehicleData->time > maxStartTime) {
                maxStartTime = vehicleData->time;
            }
        }
        
//        CCLog("Read line %d", lineIndex);
        lineIndex++;
    }
}

VehicleData* InputData::createVehicleDataFromLine(string line) {
    vector<string> elem = split(line, '\t');
    VehicleData* vehicleData = new VehicleData();
    int valueInt;
    float valueFloat;
    string valueString;
    
    int i = 0;
    int numValue = elem.size();
    if(numValue == kNumFieldData || numValue == kNumFieldData - 1) {
        
        // time
        valueString = elem[i];
        int timeValue = getTimeValue(valueString);
        if(timeValue != -1) {
            vehicleData->time = timeValue;
        }
        else {
            vehicleData->release();
            return 0;
        }
        i++;
        
        // vehicle type
        valueString = elem[i];
        valueInt = atoi(valueString.c_str());
        vehicleData->vehicleType = valueInt;
        i++;
        
        // start lane
        valueString = elem[i];
        valueInt = atoi(valueString.c_str());
        vehicleData->startLane = valueInt;
        i++;
        
        // start v
        valueString = elem[i];
        valueFloat = atof(valueString.c_str());
        vehicleData->startV = valueFloat;
        i++;
        
        // expect v
        valueString = elem[i];
        valueFloat = atof(valueString.c_str());
        vehicleData->expectV = valueFloat;
        i++;
        
        // a
        valueString = elem[i];
        valueFloat = atof(valueString.c_str());
        vehicleData->a = valueFloat;
        i++;
        
        // decrease a
        valueString = elem[i];
        valueFloat = atof(valueString.c_str());
        vehicleData->decreaseA = valueFloat;
        i++;
        
        // distance when waiting red light
        valueString = elem[i];
        valueFloat = atof(valueString.c_str());
        vehicleData->distanceWhenWaitingRedLight = valueFloat;
        i++;
        
        if(vehicleData->vehicleType == ID_SMALL_MOTO) {
            
            // moto v when change lane
            valueString = elem[i];
            valueFloat = atof(valueString.c_str());
            vehicleData->vChangeLane = valueFloat;
            i++;
            
            // moto v when change lane
            valueString = elem[i];
            valueFloat = atof(valueString.c_str());
            vehicleData->vPassBus = valueFloat;
            i++;
        }
        else {
            i += 2;
        }
        
        if(vehicleData->vehicleType == ID_BIG_MOTO) {
            
            // big moto v when change lane
            valueString = elem[i];
            valueFloat = atof(valueString.c_str());
            vehicleData->vChangeLane = valueFloat;
            i++;
            
            // big moto v when change lane
            if(i < numValue) {
                valueString = elem[i];
                valueFloat = atof(valueString.c_str());
                vehicleData->vPassBus = valueFloat;
                i++;
            }
        }
        else {
            i += 2;
        }
        
        if(i < numValue) {
            // is change lane
            valueString = elem[i];
            valueInt = atoi(valueString.c_str());
            if(valueInt == 0) {
                vehicleData->isChangeLane = false;
            }
            else {
                vehicleData->isChangeLane = true;
            }
            
            i++;
        }
    }
    else {
        CCLog("Data not correct number field");
    }
    return vehicleData;
}

int InputData::getTimeValue(string timeString) {
    vector<string> elem = split(timeString, ':');
    if(elem.size() == 3) {
        string hourString = elem[0];
        int hour = atoi(hourString.c_str());
        
        string minuteString = elem[1];
        int minute = atoi(minuteString.c_str());
        
        string secondString = elem[2];
        int second = atoi(secondString.c_str());
        
        return hour*3600 + minute*60 + second;
    }
    else {
        CCLog("Invalid time: %s", timeString.c_str());
    }
    return -1;
}

InputData::~InputData() {
    vehicleDataArray->release();
}

int InputData::getMinStartTime() {
    return minStartTime;
}

int InputData::getMaxStartTime() {
    return maxStartTime;
}

CCArray* InputData::getVehicleDataArray() {
    return vehicleDataArray;
}

CCArray* InputData::getVehicleDataArrayAtTime(int atTime) {
    CCArray* vehicleArray = CCArray::create();
    
    CCObject* it = 0;
    CCARRAY_FOREACH(vehicleDataArray, it) {
        VehicleData* vehicleData = (VehicleData*)it;
        if(vehicleData->time == atTime) {
            vehicleArray->addObject(vehicleData);
        }
    }
    
    return vehicleArray;
}

int compare(const void* left, const void* right) {
    VehicleData* leftVehicleData = (VehicleData*)left;
    VehicleData* rightVehicleData = (VehicleData*)right;
    return leftVehicleData->time > rightVehicleData->time;
}

void InputData::sortByTime() {
    sort(vehicleDataArray->data->arr, vehicleDataArray->data->arr + vehicleDataArray->data->num, compare);
}

CCString* InputData::description() {
    char buffer[1000];
    string str;
    CCObject* it;
    int i = 0;
    CCARRAY_FOREACH(vehicleDataArray, it) {
        VehicleData* vehicleData = (VehicleData*)it;
        sprintf(buffer, "%d %s\n", i, vehicleData->description()->getCString());
        str += buffer;
        i++;
    }
    CCString* ccString = CCString::create(str);
    return ccString;
}

void InputData::print() {
    CCObject* it;
    int i = 0;
    CCARRAY_FOREACH(vehicleDataArray, it) {
        VehicleData* vehicleData = (VehicleData*)it;
        CCLog("%d. %s", i, vehicleData->description()->getCString());
        i++;
    }
}

CCArray* InputData::getObjectsAndRemove(int time) {
    CCArray* resultArray = CCArray::create();
    
    CCObject* it = 0;
    CCARRAY_FOREACH(vehicleDataArray, it) {
        VehicleData* vehicleData = (VehicleData*)it;
        if(vehicleData->time < time) {
            resultArray->addObject(vehicleData);
        }
    }
    
    vehicleDataArray->removeObjectsInArray(resultArray);
    return resultArray;
}